using UnityEngine;
using System.Collections;

/// <summary>
/// Provides functionality to control the 2D Camera View. 
/// </summary>
[ExecuteInEditMode]
public class OTView : MonoBehaviour
{
    //----------------------------------------------------------------------
    // Public properties
    //----------------------------------------------------------------------
    /// <summary>
    /// Camera view zoom value. zoom out &lt; 0 &gt; zoom in.
    /// </summary>
    /// <remarks>
    /// Positive zoom values will zoom in where a value of 1 will double the size of your sprites. 
    /// Negative zoom values will zoom out where a value of -1 will half the size of your sprites.
    /// A value of 0 (zero) should display the actual (pixel) size. Note that the actual pizel size 
    /// will only be pixel perfect when <see cref="OTView.alwaysPixelPerfect"/> is set to true or when the current 
    /// resolution is the <see cref="OTView.pixelPerfectResolution"/>.
    /// </remarks>
    /// 
    public float zoom
    {
        get
        {
            return _zoom;
        }
        set
        {
            _zoom = value;
            Update();
        }
    }
    /// <summary>
    /// Current view position (x/y).
    /// </summary>
    /// <remarks>
    /// You can use the view's position to scroll or move the camera/view around in your
    /// 2D world. 
    /// </remarks>
    public Vector2 position
    {
        get
        {
            return _position;
        }
        set
        {
           _position = value;
        }
    }
    /// <summary>
    /// Current camera view rotation in degrees.
    /// </summary>
    public float rotation
    {
        get
        {
            return _rotation;
        }
        set
        {
            _rotation = value;
        }
    }
    /// <summary>
    /// Pixel perfect indicator
    /// </summary>
    /// <remarks>
    /// If alwaysPixelPerfect is set to true, sprites will always be 'pixel perfect' ignoring the
    /// current (device) resolution. If you would like to use a base resolution ( that is pixel
    /// perfect ) and zoom your view depending on the current resolution, set this to false and
    /// set your pixelResolution to the resolution on which the sprites should be pixel perfect.
    /// <br></br><br></br>
    /// <strong style="color:red" >!IMPORTANT</strong> To use pixel perfect sprites Mip Mapping 
    /// and texture compression should be disabled.
    /// </remarks>
    public bool alwaysPixelPerfect
    {
        get
        {
            return _alwaysPixelPerfect;
        }
        set
        {
            _alwaysPixelPerfect = value;
            Update();
        }
    }
    /// <summary>
    /// Resolution on which sprites will be pixel perfect
    /// </summary>
    /// <remarks>
    /// Use this to set the resolution on which spritys should be pixel perfect. This setting will
    /// only be active when the alwaysPixelPerfect setting is set to false. Only the Y (height) value
    /// of the resultion is used to calculate the zooming factor.
    /// <br></br><br></br>
    /// <strong style="color:red" >!IMPORTANT</strong> To use pixel perfect sprites Mip Mapping 
    /// and texture compression should be disabled.
    /// </remarks>
    public Vector2 pixelPerfectResolution
    {
        get
        {
            return _pixelPerfectResolution;
        }
        set
        {
            _pixelPerfectResolution = value;
            if (!alwaysPixelPerfect) Update();
        }
    }

    /// <summary>
    /// Target object's position will followed.
    /// </summary>
    public GameObject movementTarget
    {
        get
        {
            return _movementTarget;
        }
        set
        {
            _movementTarget = value;
            Update();
        }
    }
		
    /// <summary>
    /// Target object's rotation will be followed.
    /// </summary>
    public GameObject rotationTarget
    {
        get
        {
            return _rotationTarget;
        }
        set
        {
            _rotationTarget = value;
            Update();
        }
    }

    /// <summary>
    /// World boundary for the view (camera)
    /// </summary>
    /// <remarks>
    /// If world boundary is set this will restrict the camera
    /// from leaving this boundary box. Setting this to Rect(0,0,0,0) 
    /// will impose no  boundary restriction.
    /// This is specified in pixel (world space) coordinates.
    /// </remarks>
    public Rect worldBounds
    {
        get
        {
            return _worldBounds;
        }
        set
        {
            _worldBounds = value;
            Update();
        }
    }

    /// <summary>
    /// Camera object belonging to this this view.
    /// </summary>
    new public Camera camera
    {
        get
        {
            return _camera;
        }
    }

    private bool IntersectRect(Rect r1, Rect r2)
    {
        return !( r2.xMin > r1.xMax
            || r2.xMax < r1.xMin
            || r2.yMin < r1.yMax
            || r2.yMax > r1.yMin
            );
    }

    /// <summary>
    /// Checks if a specific object is in view.
    /// </summary>
    /// <param name="o">Object to check</param>
    /// <returns></returns>
    public bool Contains(OTObject o)
    {
        return IntersectRect(worldRect, o.rect);
    }
    /// <summary>
    /// Position of the mousepointer in world coordinates.
    /// </summary>
    public Vector2 mouseWorldPosition
    {
        get
        {
           return camera.ScreenToWorldPoint(Input.mousePosition);
        }
    }
    /// <summary>
    /// Position of the mousepointer in view coordinates.
    /// </summary>
    public Vector2 mouseViewPosition
    {
        get
        {
           return camera.ScreenToViewportPoint(Input.mousePosition);
        }
    }

    /// <summary>
    /// This view's rectangle in world coordinates.
    /// </summary>
    public Rect worldRect
    {
        get
        {
            Vector2 tl = camera.ViewportToWorldPoint(new Vector2(0, 0));
            Vector2 br = camera.ViewportToWorldPoint(new Vector2(1, 1));
            Vector2 si = new Vector2(br.x - tl.x, br.y - tl.y);
            return new Rect(
                camera.transform.position.x - si.x/2,
                camera.transform.position.y + si.y/2,
                si.x,
                si.y * -1);
        }
    }

    private Camera _camera
    {
        get
        {
            return Camera.main;
        }
    }

    //----------------------------------------------------------------------
    /// <exclude />
    public float _zoom = 0f;
    /// <exclude />
    public Vector2 _position = Vector2.zero;
    /// <exclude />
    public float _rotation = 0;
    /// <exclude />
    public GameObject _movementTarget = null;
    /// <exclude />
    public GameObject _rotationTarget = null;
    /// <exclude />
    public Rect _worldBounds = new Rect(0, 0, 0, 0);
    /// <exclude />
    public bool _alwaysPixelPerfect = true;
    /// <exclude />
    public Vector2 _pixelPerfectResolution = new Vector2(1024, 768);

    float resSize
    {
        get
        {
            if (alwaysPixelPerfect)
                return ((float)Screen.height / 500f) * 250f;
            else
                //    return ((pixelPerfectResolution.y / 500) * (250 * (pixelPerfectResolution.y/Screen.height)));
                return ((float)Screen.height / 500f) * 250f * (pixelPerfectResolution.y/ (float)Screen.height);
        }
    }
    /// <exclude />
    public void InitView()
    {
        SetCamera();
    }

    void SetCamera()
    {
        camera.orthographic = true;
        camera.orthographicSize = resSize * Mathf.Pow(2, _zoom * -1);
        camera.near = 0;
        camera.far = 2001;
        camera.transform.position = new Vector3(0, 0, -1001);
    }

    // Update is called once per frame
    /// <exclude />
    public void Update()
    {
		if (!OT.isValid) return;
		
        // check camera type
        if (!camera.orthographic)
            SetCamera();

        // check camera size
        if (camera.orthographicSize != resSize * (Mathf.Pow(2, _zoom * -1)))
            camera.orthographicSize = resSize * Mathf.Pow(2, _zoom * -1);

        Vector2 pos = OT.view.position;
        if (OT.view.movementTarget != null)
		    pos = OT.view.movementTarget.transform.position;

        if (worldBounds.width != 0)
        {
            float minX = _worldBounds.xMin;
            float maxX = _worldBounds.xMax;
            float minY = _worldBounds.yMin;
            float maxY = _worldBounds.yMax;
            pos.x = Mathf.Clamp(pos.x, minX, maxX);
            pos.y = Mathf.Clamp(pos.y, minY, maxY);
            position = pos;
        }
        else
            position = pos;

        if (OT.view.rotationTarget != null)
            OT.view.rotation = OT.view.rotationTarget.transform.eulerAngles.z;

        // check camera position
        if (camera.transform.position.x != _position.x || Camera.main.transform.position.y != _position.y || Camera.main.transform.position.z != -1001)
        {
            camera.transform.position = new Vector3(_position.x, _position.y, -1001);
            transform.position = camera.transform.position;
        }

        // check camera position
        if (camera.transform.eulerAngles.z != _rotation)
        {
            camera.transform.eulerAngles = new Vector3(0, 0, _rotation);
            transform.rotation = camera.transform.rotation;
        }

    }

    //void OnGUI()
    //{
    //    GUI.Box(new Rect((Screen.width / 2) - 50, (Screen.height / 2) - 50, 100, 100), "");
    //}

}